package fileDemo;



import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 2021-05-12 14:18:10
 *  datatool 中zip photo excel已测试。其他待测试。
 *
 */
public class ZipUtils {
    public static final String TAG="ZIP";


    //先进行 utf-8 ，Exception 后进行 GBK 处理。如果有问题throw exception
    public static void unZipFolder_UTF8AndGBK(String zipFileString, String outPathString) throws Exception {
        //先进性UTF-8
        try {
            unZipFolder(zipFileString,outPathString);
        } catch (Exception e) {
            //如果有问题throw exception
           unzipFileGBK(zipFileString,outPathString);
        }
    }

    //unzip-utf-8 已测试。
    //不进行递归解压缩。zip内部的zip，不进行处理。
    //win压缩10人照片-有嵌套文件夹.zip 解压。失败 java.lang.IllegalArgumentException: MALFORMED
    //其他正常。没有乱码。
    private static void unZipFolder(String zipFileString, String outPathString) throws Exception {
        unZipFolder(zipFileString,StandardCharsets.UTF_8,outPathString);
    }
    //不进行递归解压缩。zip内部的zip，不进行处理。
    public static void unZipFolder(String zipFileString, Charset charset,String outPathString) throws Exception {
        ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString),charset);
        ZipEntry zipEntry;
        String  szName = "";
        while ((zipEntry = inZip.getNextEntry()) != null) {
            szName = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                //获取部件的文件夹名
                szName = szName.substring(0, szName.length() - 1);
                File folder = new File(outPathString + File.separator + szName);
                folder.mkdirs();
            } else {
                System.out.println("ZipUtils:unZipFolder:"+outPathString + File.separator + szName);
                File file = new File(outPathString + File.separator + szName);
                if (!file.exists()){
                    System.out.println("ZipUtils:unZipFolder:Create the file:" + outPathString + File.separator + szName);
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
                // 获取文件的输出流
                FileOutputStream out = new FileOutputStream(file);
                int len;
                byte[] buffer = new byte[1024];
                // 读取（字节）字节到缓冲区
                while ((len = inZip.read(buffer)) != -1) {
                    // 从缓冲区（0）位置写入（字节）字节
                    out.write(buffer, 0, len);
                    out.flush();
                }
                out.close();
            }
        }
        inZip.close();
    }

    //其他无问题：
    // mac压缩的图片10张-无嵌套文件夹-中文名.zip 解压有问题。干扰10.jpg--->骞叉壈10.jpg
    private static void unzipFileGBK(String from, String to) throws Exception{
        byte[] buffer = new byte[4096];
        ZipInputStream zis = null;
        try {
            //create output directory is not exists
            File folder = new File(to);
            if (!folder.exists()) {
                folder.mkdir();
            }
            zis = new ZipInputStream(new FileInputStream(from), Charset.forName("GBK"));
//            ZipInputStream zis = new ZipInputStream(new FileInputStream(from), StandardCharsets.UTF_8);
            //get the zipped file list entry
            ZipEntry ze = zis.getNextEntry();
            while (ze != null) {
                String entryName = ze.getName();
                File newFileOrDirectory = new File(to + File.separator + entryName);
                if (ze.isDirectory()) {
                    newFileOrDirectory.mkdir();
                } else {
                    new File(newFileOrDirectory.getParent()).mkdirs();
                    FileOutputStream fos = new FileOutputStream(newFileOrDirectory);
                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                        fos.write(buffer, 0, len);
                    }
                    fos.close();
                }
                ze = zis.getNextEntry();
            }
            zis.closeEntry();
            zis.close();
        } catch (Exception e) {
            throw e;
        }finally {
            if (zis != null) {
                try {
                    zis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 返回zip的文件输入流
     * @param zipFileString  zip的名称
     * @param fileString     ZIP的文件名
     * @return InputStream
     * @throws Exception
     */
    public static InputStream upZip(String zipFileString, String fileString)throws Exception {
        ZipFile zipFile = new ZipFile(zipFileString);
        ZipEntry zipEntry = zipFile.getEntry(fileString);
        return zipFile.getInputStream(zipEntry);
    }


    //datatool 中zip photo excel已测试。其他待测试。
    public static void zipFolder(String srcFileString, String zipFileString) throws IOException {
        File targetFile = new File(zipFileString);
        if (targetFile.exists()) {
            targetFile.delete();
        }
        //创建ZIP
        ZipOutputStream outZip = null;
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFileString);
            outZip = new ZipOutputStream(fileOutputStream);
            //创建文件
            File file = new File(srcFileString);
            //压缩
            zipFiles(file.getParent()+File.separator, file.getName(), outZip);
            //完成和关闭
            fileOutputStream.getFD().sync();
            outZip.flush();
            outZip.finish();

        } catch (IOException e) {
            throw e;
        } finally {
            if (outZip != null) {
                outZip.close();
            }
        }
    }

    /**
     * 压缩文件
     * @param folderString
     * @param fileString
     * @param zipOutputSteam
     * @throws Exception
     */
    private static void zipFiles(String folderString, String fileString,
            ZipOutputStream zipOutputSteam) throws IOException {
        if(zipOutputSteam == null) {
            return;
        }

        File file = new File(folderString+fileString);
        FileInputStream inputStream = null;
        if (file.isFile()) {
            try {
                inputStream = new FileInputStream(file);
                ZipEntry zipEntry =  new ZipEntry(fileString);
                zipOutputSteam.putNextEntry(zipEntry);
                int len;
                byte[] buffer = new byte[4096];
                while((len=inputStream.read(buffer)) != -1)
                {
                    zipOutputSteam.write(buffer, 0, len);
                }
                zipOutputSteam.flush();
                zipOutputSteam.closeEntry();
            } catch (IOException e) {
                throw e;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
            }
        }
        else {
            //文件夹
            String fileList[] = file.list();
            //没有子文件和压缩
            if (fileList.length <= 0) {
                ZipEntry zipEntry =  new ZipEntry(fileString+File.separator);
                zipOutputSteam.putNextEntry(zipEntry);
                zipOutputSteam.closeEntry();
            }
            //子文件和递归
            for (int i = 0; i < fileList.length; i++) {
                zipFiles(folderString, fileString+ File.separator+fileList[i], zipOutputSteam);
            }
        }
    }


    /**
     * 返回ZIP中的文件列表（文件和文件夹）
     * @param zipFileString     ZIP的名称
     * @param bContainFolder    是否包含文件夹
     * @param bContainFile      是否包含文件
     * @return
     * @throws Exception
     */
    public static List<File> getFileList(String zipFileString, boolean bContainFolder,
            boolean bContainFile)throws Exception {
        List<File> fileList = new ArrayList<File>();
        ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));
        ZipEntry zipEntry;
        String szName = "";
        while ((zipEntry = inZip.getNextEntry()) != null) {
            szName = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                // 获取部件的文件夹名
                szName = szName.substring(0, szName.length() - 1);
                File folder = new File(szName);
                if (bContainFolder) {
                    fileList.add(folder);
                }
            } else {
                File file = new File(szName);
                if (bContainFile) {
                    fileList.add(file);
                }
            }
        }
        inZip.close();
        return fileList;
    }
}